package com.xyht.sca_s.student_manage_system.modules.carUseReturn.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.xyht.sca_s.student_manage_system.common.commonReturn.CommonCodeEnum;
import com.xyht.sca_s.student_manage_system.common.commonReturn.CommonResult;
import com.xyht.sca_s.student_manage_system.common.commonReturn.ExceptionCast;
import com.xyht.sca_s.student_manage_system.common.commonReturn.ResponseResult;
import com.xyht.sca_s.student_manage_system.common.util.CacheUtil;
import com.xyht.sca_s.student_manage_system.modules.carUseManage.entity.Resp.SmsCarWarehousingResp;
import com.xyht.sca_s.student_manage_system.modules.carUseManage.entity.SmsCarUseApplication;
import com.xyht.sca_s.student_manage_system.modules.carUseManage.entity.SmsCarWarehousing;
import com.xyht.sca_s.student_manage_system.modules.carUseManage.mapper.SmsCarUseApplicationMapper;
import com.xyht.sca_s.student_manage_system.modules.carUseManage.mapper.SmsCarWarehousingMapper;
import com.xyht.sca_s.student_manage_system.modules.carUseReturn.entity.Resp.*;
import com.xyht.sca_s.student_manage_system.modules.carUseReturn.entity.SmsCarUseReturnApplication;
import com.xyht.sca_s.student_manage_system.modules.carUseReturn.entity.SmsCarUseReturnApplicationDetail;
import com.xyht.sca_s.student_manage_system.modules.carUseReturn.entity.SmsCarUseReturnApplicationProcess;
import com.xyht.sca_s.student_manage_system.modules.carUseReturn.entity.req.*;
import com.xyht.sca_s.student_manage_system.modules.carUseReturn.mapper.SmsCarUseReturnApplicationDetailMapper;
import com.xyht.sca_s.student_manage_system.modules.carUseReturn.mapper.SmsCarUseReturnApplicationMapper;
import com.xyht.sca_s.student_manage_system.modules.carUseReturn.mapper.SmsCarUseReturnApplicationMpjMapper;
import com.xyht.sca_s.student_manage_system.modules.carUseReturn.mapper.SmsCarUseReturnApplicationProcessMapper;
import com.xyht.sca_s.student_manage_system.modules.carUseReturn.service.SmsCarUseReturnApplicationService;
import com.xyht.sca_s.student_manage_system.modules.newTips.myEnum.AppTypeEnum;
import com.xyht.sca_s.student_manage_system.modules.newTips.myEnum.RangeTypeEnum;
import com.xyht.sca_s.student_manage_system.modules.newTips.myEnum.TipsTypeEnum;
import com.xyht.sca_s.student_manage_system.modules.newTips.util.NewTipsUtil;
import com.xyht.sca_s.student_manage_system.modules.user.entity.SmsRole;
import com.xyht.sca_s.student_manage_system.modules.user.entity.SmsUser;
import com.xyht.sca_s.student_manage_system.modules.user.mapper.SmsRoleMapper;
import com.xyht.sca_s.student_manage_system.modules.user.mapper.SmsUserMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

import static com.xyht.sca_s.student_manage_system.common.util.ParamCheckUtil.isNullOrEmpty;
import static com.xyht.sca_s.student_manage_system.modules.carUseManage.constant.carStatusConstant.*;
import static com.xyht.sca_s.student_manage_system.modules.carUseManage.constant.carUseApplicationStatusConstant.*;
import static com.xyht.sca_s.student_manage_system.modules.carUseManage.constant.carUseApplicationTypeConstant.*;
import static com.xyht.sca_s.student_manage_system.modules.carUseManage.constant.carUseObjectTypeConstant.CAR_USE_OBJECT_TYPE_PERSON;
import static com.xyht.sca_s.student_manage_system.modules.carUseManage.constant.carUseObjectTypeConstant.CAR_USE_OBJECT_TYPE_ROLE;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author XYHT
 * @since 2023-08-02
 */
@Service
public class SmsCarUseReturnApplicationServiceImpl extends ServiceImpl<SmsCarUseReturnApplicationMapper, SmsCarUseReturnApplication> implements SmsCarUseReturnApplicationService {
    @Autowired
    SmsCarUseReturnApplicationMapper smsCarUseReturnApplicationMapper;
    @Autowired
    SmsCarUseReturnApplicationProcessMapper smsCarUseReturnApplicationProcessMapper;
    @Autowired
    SmsCarUseReturnApplicationDetailMapper smsCarUseReturnApplicationDetailMapper;
    @Autowired
    NewTipsUtil newTipsUtil;
    @Autowired
    SmsCarWarehousingMapper smsCarWarehousingMapper;
    @Autowired
    CacheUtil cacheUtil;
    @Autowired
    SmsCarUseReturnApplicationMpjMapper smsCarUseReturnApplicationMpjMapper;
    @Autowired
    SmsUserMapper smsUserMapper;
    @Autowired
    SmsRoleMapper smsRoleMapper;
    @Autowired
    SmsCarUseApplicationMapper smsCarUseApplicationMapper;


    @Transactional
    @Override
    public ResponseResult returnApplication(SmsCarUseReturnApplicationReq applicationReq, String userId) {
        List<SmsCarUseReturnApplicationProcess> fillProcessList =
                smsCarUseReturnApplicationProcessMapper.selectList(new QueryWrapper<SmsCarUseReturnApplicationProcess>()
                        .lambda()
                        .eq(SmsCarUseReturnApplicationProcess::getProcessIsApplicationEdit, true)
                        .eq(SmsCarUseReturnApplicationProcess::getProcessIsUse, true)
                        .orderByAsc(SmsCarUseReturnApplicationProcess::getProcessSort));
        if (fillProcessList != null && fillProcessList.size() > 0) {
            if (applicationReq.getProcessList() == null || applicationReq.getProcessList().size() < 1) {
                return CommonResult.failed(CommonCodeEnum.CAR_USE_RETURN_ALLOW_USER_NOT_SETTING);
            }
            //判断申请人是否将全部需要编辑流程填写
            List<SmsCarUseReturnApplicationProcess> filterList = fillProcessList
                    .stream()
                    .filter(process -> {
                                List<String> result = applicationReq.getProcessList()
                                        .stream()
                                        .filter(fillProcess -> fillProcess.getProcessId().equals(process.getId()))
                                        .map(SmsCarUseReturnApplicationDetailReq::getId)
                                        .collect(Collectors.toList());
                                //匹配的去除  未匹配的留下
                                if (result.size() > 0) {
                                    return false;
                                } else {
                                    return true;
                                }
                            }
                    )
                    .collect(Collectors.toList());
            if (filterList.size() > 0) {
                return CommonResult.failed(CommonCodeEnum.CAR_USE_ALLOW_PROCESS_NOT_FILL);
            }
        }


        //创建申请表
        SmsCarUseReturnApplication smsCarUseApplication = new SmsCarUseReturnApplication();
        BeanUtils.copyProperties(applicationReq, smsCarUseApplication);
        smsCarUseApplication.setReturnApplyUserId(userId);
        QueryWrapper<SmsCarWarehousing> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(SmsCarWarehousing::getId,smsCarUseApplication.getCarId());
        SmsCarWarehousing warehousing = smsCarWarehousingMapper.selectOne(queryWrapper);
        if(isNullOrEmpty(warehousing)){
            return CommonResult.failed(CommonCodeEnum.DATA_NOT_FOUND);
        }
        smsCarUseApplication.setCarName(warehousing.getCarName());
        smsCarUseApplication.setCarPic(warehousing.getCarPic());
        smsCarUseApplication.setCarPosition(warehousing.getCarPosition());
        smsCarUseApplication.setCarNum(warehousing.getCarNum());
        smsCarUseApplication.setAllowStatus(CAR_USE_STATUS_WAIT_ALLOW);
        smsCarUseReturnApplicationMapper.insert(smsCarUseApplication);

        if (smsCarUseApplication.getId() == null) {
            ExceptionCast.cast(CommonResult.failed(CommonCodeEnum.FAIL));
        }
        String application_id = smsCarUseApplication.getId();

        //创建审批流程
        List<SmsCarUseReturnApplicationProcess> originProcessList =
                smsCarUseReturnApplicationProcessMapper.selectList(new QueryWrapper<SmsCarUseReturnApplicationProcess>()
                        .lambda()
                        .eq(SmsCarUseReturnApplicationProcess::getProcessIsUse, true)
                        .orderByAsc(SmsCarUseReturnApplicationProcess::getProcessSort));
        if (originProcessList == null || originProcessList.size() < 1) {
            ExceptionCast.cast(CommonResult.failed(CommonCodeEnum.CAR_USE_PROCESS_NOT_SETTING));
        }
        int sort = 1;
        for (SmsCarUseReturnApplicationProcess process : originProcessList) {
            //判断管理员是否配置初始流程
            if (!process.getProcessIsApplicationEdit()) {
                if (isNullOrEmpty(process.getProcessObjectId()) || isNullOrEmpty(process.getProcessObjectType())) {
                    ExceptionCast.cast(CommonResult.failed(CommonCodeEnum.CAR_USE_PROCESS_NOT_SETTING));
                }
            }

            SmsCarUseReturnApplicationDetail addDetail =
                    new SmsCarUseReturnApplicationDetail();

            addDetail.setApplicationId(application_id);
            addDetail.setProcessId(process.getId());
            addDetail.setProcessIsSign(process.getProcessIsSign());
            addDetail.setProcessIsStamp(process.getProcessIsStamp());
            addDetail.setProcessName(process.getProcessName());
            addDetail.setDetailAllowStatus(CAR_USE_STATUS_WAIT_ALLOW);

            addDetail.setDetailSort(sort++);


            //申请人可编辑流程
            if (process.getProcessIsApplicationEdit()) {
                List<SmsCarUseReturnApplicationDetailReq> filterList = applicationReq.getProcessList()
                        .stream()
                        .filter(fillProcess -> fillProcess.getProcessId().equals(process.getId()))
                        .collect(Collectors.toList());
                if (filterList.size() < 1) {
                    ExceptionCast.cast(CommonResult.failed(CommonCodeEnum.CAR_USE_ALLOW_PROCESS_NOT_FILL));
                }
                SmsCarUseReturnApplicationDetailReq fillProcessReq = filterList.get(0);

                if (isNullOrEmpty(fillProcessReq.getProcessObjectId())) {
                    ExceptionCast.cast(CommonResult.failed(CommonCodeEnum.INVALID_PARAM));
                }
                addDetail.setProcessObjectId(fillProcessReq.getProcessObjectId());
                addDetail.setProcessObjectType(fillProcessReq.getProcessObjectType());
            } else {
                addDetail.setProcessObjectId(process.getProcessObjectId());
                addDetail.setProcessObjectType(process.getProcessObjectType());
            }
            smsCarUseReturnApplicationDetailMapper.insert(addDetail);
        }
        //消息通知
        //通知流程第一个节点
        SmsCarUseReturnApplicationDetail firstDetail =
                smsCarUseReturnApplicationDetailMapper.selectOne(new QueryWrapper<SmsCarUseReturnApplicationDetail>()
                        .lambda()
                        .eq(SmsCarUseReturnApplicationDetail::getApplicationId, application_id)
                        .eq(SmsCarUseReturnApplicationDetail::getDetailSort, 1)
                        .orderByAsc(SmsCarUseReturnApplicationDetail::getDetailSort));
        RangeTypeEnum rangeTypeEnum;
        if (firstDetail.getProcessIsApplicationEdit().equals(1)) {
            rangeTypeEnum = RangeTypeEnum.RANGE_TYPE_ENUM_PERSON;
        } else {
            if (firstDetail.getProcessObjectType() == CAR_USE_OBJECT_TYPE_PERSON) {
                rangeTypeEnum = RangeTypeEnum.RANGE_TYPE_ENUM_PERSON;
            } else {
                rangeTypeEnum = RangeTypeEnum.RANGE_TYPE_ENUM_ROLE;
            }
        }

        List<String> rangeList = new ArrayList<>();
        rangeList.add(firstDetail.getProcessObjectId());
        newTipsUtil.addNewTips(TipsTypeEnum.TIPS_TYPE_ENUM_ALLOW,
                userId,
                rangeTypeEnum,
                rangeList,
                AppTypeEnum.APP_TYPE_ENUM_CAR_RETURN,
                application_id,
                firstDetail.getId());
        return CommonResult.success();
    }

    @Transactional
    @Override
    public ResponseResult cancelApplication(SmsCarUseReturnApplicationCancelReq cancelReq, String userId) {
        if (isNullOrEmpty(cancelReq.getApplyId())) {
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }

        //查看审批表是否存在且是否为本人
        SmsCarUseReturnApplication application =
                smsCarUseReturnApplicationMapper.selectOne(new QueryWrapper<SmsCarUseReturnApplication>()
                        .lambda()
                        .eq(SmsCarUseReturnApplication::getId, cancelReq.getApplyId())
                        .eq(SmsCarUseReturnApplication::getReturnApplyUserId, userId));
        if (application == null || isNullOrEmpty(application.getId())) {
            return CommonResult.failed(CommonCodeEnum.CAR_USE_NOT_EXIST);
        }
        if (application.getAllowStatus() != CAR_USE_STATUS_WAIT_ALLOW) {
            return CommonResult.failed(CommonCodeEnum.CAR_USE_CANCEL_FAIL_ALLOWED);
        }

        //判断是否审批中
//        List<SmsCarUseApplicationDetail> detailList =
//                smsCarUseApplicationDetailMapper.selectList(new QueryWrapper<SmsCarUseApplicationDetail>()
//                        .lambda()
//                        .eq(SmsCarUseApplicationDetail::getApplicationId, cancelReq.getApplyId())
//                        .eq(SmsCarUseApplicationDetail::getDetailAllowStatus, CAR_USE_STATUS_PASS));
//        if (detailList != null && detailList.size() > 0) {
//            return CommonResult.failed(CommonCodeEnum.CAR_USE_CANCEL_FAIL_ALLOWING);
//        }

        //撤回审批
        SmsCarUseReturnApplication cancelApplication = new SmsCarUseReturnApplication();
        cancelApplication.setId(cancelReq.getApplyId());
        cancelApplication.setAllowStatus(CAR_USE_STATUS_CANCEL);
        cancelApplication.setEndTime(new Date());
        smsCarUseReturnApplicationMapper.updateById(cancelApplication);

        //修改节点状态
        SmsCarUseReturnApplicationDetail cancelApplicationDetail = new SmsCarUseReturnApplicationDetail();
        cancelApplicationDetail.setDetailAllowStatus(CAR_USE_STATUS_CANCEL);

        smsCarUseReturnApplicationDetailMapper.update(cancelApplicationDetail, new QueryWrapper<SmsCarUseReturnApplicationDetail>()
                .lambda()
                .eq(SmsCarUseReturnApplicationDetail::getApplicationId, cancelReq.getApplyId())
                .eq(SmsCarUseReturnApplicationDetail::getDetailAllowStatus, CAR_USE_STATUS_WAIT_ALLOW));

        //消息通知
        newTipsUtil.cancelFinishTips(cancelReq.getApplyId());
        return CommonResult.success();
    }

    @Override
    public ResponseResult getList(Integer pageSize, String search_str,Integer pageNum, Integer apply_type, String userId) {
        if (isNullOrEmpty(apply_type)) {
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }
        List<SmsCarUseReturnApplicationResp> respList = new ArrayList<>();
        int total = 0;
        if (apply_type == CAR_USE_TYPE_APPLY) {
            Page<SmsCarUseReturnApplication> page = new Page<>(pageNum, pageSize);
            QueryWrapper<SmsCarUseReturnApplication> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda()
                    .eq(SmsCarUseReturnApplication::getReturnApplyUserId, userId)
                    .orderByDesc(SmsCarUseReturnApplication::getCreateTime);
            if(!isNullOrEmpty(search_str)){
                queryWrapper.lambda().like(SmsCarUseReturnApplication::getReturnApplyDepartment,search_str);
            }
            smsCarUseReturnApplicationMapper.selectPage(page, queryWrapper);
            respList = page.getRecords()
                    .stream()
                    .map(smsCarUseReturnApplication -> {
                        SmsCarUseReturnApplicationResp smsCarUseApplicationResp =
                                new SmsCarUseReturnApplicationResp();
                        BeanUtils.copyProperties(smsCarUseReturnApplication, smsCarUseApplicationResp);
                        smsCarUseApplicationResp.setApplicationId(smsCarUseReturnApplication.getId());

                        SmsUser smsUser = cacheUtil.getUserInfo(smsCarUseReturnApplication.getReturnApplyUserId());
                        SmsCarUseReturnApplicationUserResp smsCarUseApplicationUserResp = new SmsCarUseReturnApplicationUserResp();
                        if (smsUser != null) {
                            BeanUtils.copyProperties(smsUser, smsCarUseApplicationUserResp);
                        }
                        smsCarUseApplicationResp.setApplyUserInfo(smsCarUseApplicationUserResp);

                        return smsCarUseApplicationResp;
                    })
                    .collect(Collectors.toList());
            total = (int) page.getTotal();
        } else if (apply_type == CAR_USE_TYPE_ALLOWED) {
            Page<SmsCarUseReturnApplicationMPJResp> page = new Page<>(pageNum, pageSize);
            MPJLambdaWrapper<SmsCarUseReturnApplicationDetail> mpjLambdaWrapper = new MPJLambdaWrapper<>();
            mpjLambdaWrapper.selectAll(SmsCarUseReturnApplicationDetail.class)
                    .selectAll(SmsCarUseReturnApplication.class)
                    .selectAs(SmsCarUseReturnApplication::getCreateTime, "createTime")
                    .selectAs(SmsCarUseReturnApplicationDetail::getId, "detailId")
                    .leftJoin(SmsCarUseReturnApplication.class, SmsCarUseReturnApplication::getId, SmsCarUseReturnApplicationDetail::getApplicationId)
                    .eq(SmsCarUseReturnApplicationDetail::getDetailAllowUserId, userId)
                    .orderByDesc(SmsCarUseReturnApplicationDetail::getDetailAllowTime)
            ;
            mpjLambdaWrapper.and(wrapper -> {
                wrapper.eq(SmsCarUseReturnApplicationDetail::getDetailAllowStatus, CAR_USE_STATUS_PASS)
                        .or()
                        .eq(SmsCarUseReturnApplicationDetail::getDetailAllowStatus, CAR_USE_STATUS_DENY);
            });
            if(!isNullOrEmpty(search_str)){
                List<String> userIds = smsUserMapper.selectList(new QueryWrapper<SmsUser>()
                        .lambda()
                        .like(SmsUser::getRealName, search_str))
                        .stream()
                        .map(SmsUser::getId).collect(Collectors.toList());

                mpjLambdaWrapper.and(q ->{
                    q.like(SmsCarUseReturnApplication::getReturnApplyDepartment,search_str);
                    if(userIds.size() > 0) {
                        q.or().in(SmsCarUseReturnApplication::getReturnApplyUserId, userIds);
                    }
                });
            }
            smsCarUseReturnApplicationMpjMapper.selectJoinPage(page, SmsCarUseReturnApplicationMPJResp.class, mpjLambdaWrapper);

            respList = page.getRecords()
                    .stream()
                    .map(smsCarUseMPJResp -> {
                        SmsCarUseReturnApplicationResp smsCarUseApplicationResp = new SmsCarUseReturnApplicationResp();
                        BeanUtils.copyProperties(smsCarUseMPJResp, smsCarUseApplicationResp);
                        smsCarUseApplicationResp.setCreateTime(smsCarUseMPJResp.getCreateTime());

                        SmsUser applyUser = cacheUtil.getUserInfo(smsCarUseApplicationResp.getReturnApplyUserId());
                        SmsCarUseReturnApplicationUserResp smsCarUseApplicationUserResp = new SmsCarUseReturnApplicationUserResp();
                        if (applyUser != null) {
                            BeanUtils.copyProperties(applyUser, smsCarUseApplicationUserResp);
                        }
                        smsCarUseApplicationResp.setApplyUserInfo(smsCarUseApplicationUserResp);

                        SmsUser allowUser = cacheUtil.getUserInfo(smsCarUseApplicationResp.getDetailAllowUserId());
                        SmsCarUseReturnApplicationUserResp smsApplicationAllowUserResp = new SmsCarUseReturnApplicationUserResp();
                        if (allowUser != null) {
                            BeanUtils.copyProperties(allowUser, smsApplicationAllowUserResp);
                        }
                        smsCarUseApplicationResp.setAllowUserInfo(smsApplicationAllowUserResp);

                        return smsCarUseApplicationResp;
                    })
                    .collect(Collectors.toList());
            total = (int) page.getTotal();
        } else if (apply_type == CAR_USE_TYPE_ALLOW_WAIT_ME) {
            List<String> roleList = cacheUtil.getRoleList(userId);

            //获取所有待审批申请流程节点
            List<SmsCarUseReturnApplicationDetail> allDetailList =
                    smsCarUseReturnApplicationDetailMapper.selectList(new QueryWrapper<SmsCarUseReturnApplicationDetail>()
                            .lambda()
                            .eq(SmsCarUseReturnApplicationDetail::getDetailAllowStatus, CAR_USE_STATUS_WAIT_ALLOW));

            List<SmsCarUseReturnApplicationDetail> filterDetailList = allDetailList.stream()
                    .filter(detail -> {
                        if (detail.getProcessIsApplicationEdit().equals(1)) {
                            if (!detail.getProcessObjectId().equals(userId)) {
                                return false;
                            }
                        } else {
                            if (detail.getProcessObjectType() == CAR_USE_OBJECT_TYPE_PERSON) {
                                if (!detail.getProcessObjectId().equals(userId)) {
                                    return false;
                                }
                            } else {
                                List<String> filterRoleList = roleList.stream().filter(role -> role.equals(detail.getProcessObjectId())).collect(Collectors.toList());
                                if (filterRoleList.size() < 1) {
                                    return false;
                                }
                            }
                        }


                        if (detail.getDetailSort().equals(1)) {
                            return true;
                        }
                        //判断上一个流程节点是否完成
                        SmsCarUseReturnApplicationDetail preDetail =
                                smsCarUseReturnApplicationDetailMapper.selectOne(new QueryWrapper<SmsCarUseReturnApplicationDetail>()
                                        .lambda()
                                        .eq(SmsCarUseReturnApplicationDetail::getApplicationId, detail.getApplicationId())
                                        .eq(SmsCarUseReturnApplicationDetail::getDetailSort, detail.getDetailSort() - 1)
                                        .eq(SmsCarUseReturnApplicationDetail::getDetailAllowStatus, CAR_USE_STATUS_PASS));
                        if (preDetail == null || isNullOrEmpty(preDetail.getId())) {
                            return false;
                        }
                        return true;
                    })
                    .collect(Collectors.toList());
            if (filterDetailList.size() > 0) {
                List<String> detailIDList = filterDetailList.stream().map(SmsCarUseReturnApplicationDetail::getId).collect(Collectors.toList());

                Page<SmsCarUseReturnApplicationMPJResp> page = new Page<>(pageNum, pageSize);
                MPJLambdaWrapper<SmsCarUseReturnApplicationDetail> mpjLambdaWrapper = new MPJLambdaWrapper<>();
                mpjLambdaWrapper.selectAll(SmsCarUseReturnApplicationDetail.class)
                        .selectAll(SmsCarUseReturnApplication.class)
                        .selectAs(SmsCarUseReturnApplication::getCreateTime, "createTime")
                        .selectAs(SmsCarUseReturnApplicationDetail::getId, "detailId")
                        .leftJoin(SmsCarUseReturnApplication.class, SmsCarUseReturnApplication::getId, SmsCarUseReturnApplicationDetail::getApplicationId)
                        .in(SmsCarUseReturnApplicationDetail::getId, detailIDList)
                        .orderByDesc(SmsCarUseReturnApplication::getCreateTime)
                        .orderByDesc(SmsCarUseReturnApplicationDetail::getDetailAllowTime)
                ;
                if(!isNullOrEmpty(search_str)){
                    List<String> userIds = smsUserMapper.selectList(new QueryWrapper<SmsUser>()
                            .lambda()
                            .like(SmsUser::getRealName, search_str))
                            .stream()
                            .map(SmsUser::getId).collect(Collectors.toList());

                    mpjLambdaWrapper.and(q ->{
                        q.like(SmsCarUseReturnApplication::getReturnApplyDepartment,search_str);
                        if(userIds.size() > 0) {
                            q.or().in(SmsCarUseReturnApplication::getReturnApplyUserId, userIds);
                        }
                    });
                }
                smsCarUseReturnApplicationMpjMapper.selectJoinPage(page, SmsCarUseReturnApplicationMPJResp.class, mpjLambdaWrapper);

                respList = page.getRecords()
                        .stream()
                        .map(smsApplicationMPJResp -> {
                            SmsCarUseReturnApplicationResp smsApplicationResp = new SmsCarUseReturnApplicationResp();
                            BeanUtils.copyProperties(smsApplicationMPJResp, smsApplicationResp);
                            smsApplicationResp.setApplicationId(smsApplicationMPJResp.getApplicationId());
                            smsApplicationResp.setCreateTime(smsApplicationMPJResp.getCreateTime());

                            SmsUser applyUser = cacheUtil.getUserInfo(smsApplicationResp.getReturnApplyUserId());
                            SmsCarUseReturnApplicationUserResp smsApplicationUserResp = new SmsCarUseReturnApplicationUserResp();
                            if (applyUser != null) {
                                BeanUtils.copyProperties(applyUser, smsApplicationUserResp);
                            }
                            smsApplicationResp.setApplyUserInfo(smsApplicationUserResp);

                            return smsApplicationResp;
                        })
                        .collect(Collectors.toList());
                total = (int) page.getTotal();

            }
        }
        return CommonResult.success(respList, total);
    }

    @Override
    public ResponseResult getDetail(String apply_id, String userId) {
        if (isNullOrEmpty(apply_id)) {
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }
        SmsCarUseReturnApplication smsCarUseApplication = smsCarUseReturnApplicationMapper.selectById(apply_id);
        if (smsCarUseApplication == null || isNullOrEmpty(smsCarUseApplication.getId())) {
            return CommonResult.failed(CommonCodeEnum.CAR_USE_NOT_EXIST);
        }

        SmsCarUseReturnApplicationResp smsCarUseApplicationResp = new SmsCarUseReturnApplicationResp();
        BeanUtils.copyProperties(smsCarUseApplication, smsCarUseApplicationResp);
        QueryWrapper<SmsCarWarehousing> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(SmsCarWarehousing::getId,smsCarUseApplicationResp.getCarId());
        SmsCarWarehousing warehousing = smsCarWarehousingMapper.selectOne(queryWrapper);
        if(isNullOrEmpty(warehousing)){
            return CommonResult.failed(CommonCodeEnum.DATA_NOT_FOUND);
        }
        smsCarUseApplicationResp.setReturnCarName(warehousing.getCarName());
        smsCarUseApplicationResp.setReturnCarNum(warehousing.getCarNum());
        smsCarUseApplicationResp.setReturnCarPic(warehousing.getCarPic());
        smsCarUseApplicationResp.setReturnCarPosition(warehousing.getCarPosition());
        smsCarUseApplicationResp.setReturnCarPower(warehousing.getCarPower());
        smsCarUseApplicationResp.setReturnCarVin(warehousing.getCarVin());
        smsCarUseApplicationResp.setReturnCarOperatingMode(warehousing.getCarOperatingMode());

        smsCarUseApplicationResp.setApplicationId(smsCarUseApplication.getId());
        SmsUser smsUser = cacheUtil.getUserInfo(smsCarUseApplicationResp.getReturnApplyUserId());
        SmsCarUseReturnApplicationUserResp smsCarUseApplicationUserResp = new SmsCarUseReturnApplicationUserResp();
        if (smsUser != null) {
            BeanUtils.copyProperties(smsUser, smsCarUseApplicationUserResp);
        }
        smsCarUseApplicationResp.setApplyUserInfo(smsCarUseApplicationUserResp);

        List<SmsCarUseReturnApplicationDetailResp> detailRespList =
                smsCarUseReturnApplicationDetailMapper.selectList(new QueryWrapper<SmsCarUseReturnApplicationDetail>()
                        .lambda()
                        .eq(SmsCarUseReturnApplicationDetail::getApplicationId, apply_id)
                        .orderByAsc(SmsCarUseReturnApplicationDetail::getDetailSort))
                        .stream()
                        .map(detail -> {
                            SmsCarUseReturnApplicationDetailResp detailResp = new SmsCarUseReturnApplicationDetailResp();
                            BeanUtils.copyProperties(detail, detailResp);
                            if (detailResp.getProcessObjectType() == CAR_USE_OBJECT_TYPE_PERSON) {
                                SmsUser smsUser1 = smsUserMapper.selectById(detailResp.getProcessObjectId());
                                detailResp.setRealName(smsUser1.getRealName());
                                detailResp.setHeadPic(smsUser1.getUserPic());
                            } else if (detailResp.getProcessObjectType() == CAR_USE_OBJECT_TYPE_ROLE) {
                                SmsRole smsRole = smsRoleMapper.selectById(detailResp.getProcessObjectId());
                                detailResp.setRealName(smsRole.getRoleName());
                            }

                            if (!isNullOrEmpty(detailResp.getDetailAllowUserId())) {
                                SmsUser userInfo = cacheUtil.getUserInfo(detailResp.getDetailAllowUserId());
                                SmsCarUseReturnApplicationUserResp applicationUserDTO = new SmsCarUseReturnApplicationUserResp();
                                if (userInfo != null) {
                                    BeanUtils.copyProperties(userInfo, applicationUserDTO);
                                }
                                detailResp.setAllowUserInfo(applicationUserDTO);
                            }
                            return detailResp;
                        })
                        .collect(Collectors.toList());
        smsCarUseApplicationResp.setDetailList(detailRespList);

        return CommonResult.success(smsCarUseApplicationResp);
    }

    @Transactional
    @Override
    public ResponseResult allowApplication(SmsCarUseReturnApplicationAllowReq allowVO, String user_id) {
        if (isNullOrEmpty(allowVO.getApplyId()) || isNullOrEmpty(allowVO.getDetailId())
                || isNullOrEmpty(allowVO.getDetailAllowStatus())) {
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }

        if (allowVO.getDetailAllowStatus() != CAR_USE_STATUS_PASS
                && allowVO.getDetailAllowStatus() != CAR_USE_STATUS_DENY) {
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }

        SmsCarUseReturnApplicationDetail applicationDetail =
                smsCarUseReturnApplicationDetailMapper.selectOne(new QueryWrapper<SmsCarUseReturnApplicationDetail>()
                        .lambda()
                        .eq(SmsCarUseReturnApplicationDetail::getApplicationId, allowVO.getApplyId())
                        .eq(SmsCarUseReturnApplicationDetail::getId, allowVO.getDetailId())
                        .eq(SmsCarUseReturnApplicationDetail::getDetailAllowStatus, CAR_USE_STATUS_WAIT_ALLOW));
        if (isNullOrEmpty(applicationDetail)) {
            return CommonResult.failed(CommonCodeEnum.CAR_USE_ALLOW_FAIL);
        }

        //判断该节点是否本人审批（防止调节点审批）
        if (applicationDetail.getProcessObjectType() == CAR_USE_OBJECT_TYPE_PERSON) {
            if (!applicationDetail.getProcessObjectId().equals(user_id)) {
                return CommonResult.failed(CommonCodeEnum.CAR_USE_ALLOW_FAIL);
            }
        } else {
            List<String> roleList = cacheUtil.getRoleList(user_id);
            List<String> filterRoleList = roleList.stream().filter(role -> role.equals(applicationDetail.getProcessObjectId())).collect(Collectors.toList());
            if (filterRoleList.size() < 1) {
                return CommonResult.failed(CommonCodeEnum.CAR_USE_ALLOW_FAIL);
            }
        }
        if (!applicationDetail.getDetailSort().equals(1)) {
            SmsCarUseReturnApplicationDetail preDetail =
                    smsCarUseReturnApplicationDetailMapper.selectOne(new QueryWrapper<SmsCarUseReturnApplicationDetail>()
                            .lambda()
                            .eq(SmsCarUseReturnApplicationDetail::getApplicationId, allowVO.getApplyId())
                            .eq(SmsCarUseReturnApplicationDetail::getDetailSort, applicationDetail.getDetailSort() - 1));
            if (preDetail != null && isNullOrEmpty(preDetail.getId())) {
                if (preDetail.getDetailAllowStatus() != CAR_USE_STATUS_PASS) {
                    return CommonResult.failed(CommonCodeEnum.CAR_USE_ALLOW_FAIL);
                }
            }
        }

        SmsCarUseReturnApplicationDetail allowDetail = new SmsCarUseReturnApplicationDetail();
        allowDetail.setId(allowVO.getDetailId());
        allowDetail.setDetailAllowStatus(allowVO.getDetailAllowStatus());
        if (!isNullOrEmpty(allowVO.getDetailAllowOption())) {
            allowDetail.setDetailAllowOption(allowVO.getDetailAllowOption());
        }
        Date nowDate = new Date();
        allowDetail.setDetailAllowTime(nowDate);
        allowDetail.setDetailAllowUserId(user_id);

        if (applicationDetail.getProcessIsSign()) {
            if (isNullOrEmpty(allowVO.getDetailAllowSign())) {
                ExceptionCast.cast(CommonResult.failed(CommonCodeEnum.INVALID_PARAM));
            }
            allowDetail.setDetailAllowSign(allowVO.getDetailAllowSign());
        }
        if (applicationDetail.getProcessIsStamp()) {
            if (isNullOrEmpty(allowVO.getDetailAllowStamp())) {
                ExceptionCast.cast(CommonResult.failed(CommonCodeEnum.INVALID_PARAM));
            }
            allowDetail.setDetailAllowStamp(allowVO.getDetailAllowStamp());
        }
        smsCarUseReturnApplicationDetailMapper.updateById(allowDetail);

        boolean is_done = false;

        //判断是否最后一个节点 是否驳回
        Integer detailCount = smsCarUseReturnApplicationDetailMapper.selectCount(new QueryWrapper<SmsCarUseReturnApplicationDetail>()
                .lambda()
                .eq(SmsCarUseReturnApplicationDetail::getApplicationId, allowVO.getApplyId()));
        if (detailCount.equals(applicationDetail.getDetailSort()) || allowVO.getDetailAllowStatus() == CAR_USE_STATUS_DENY) {
            is_done = true;

            SmsCarUseReturnApplication updateApplication = new SmsCarUseReturnApplication();
            updateApplication.setId(allowVO.getApplyId());
            updateApplication.setEndTime(nowDate);
            updateApplication.setAllowStatus(allowVO.getDetailAllowStatus());
            smsCarUseReturnApplicationMapper.updateById(updateApplication);
        }
        if (detailCount.equals(applicationDetail.getDetailSort()) && allowVO.getDetailAllowStatus() == CAR_USE_STATUS_PASS) {
            SmsCarUseReturnApplication smsCarUseApplication = smsCarUseReturnApplicationMapper.selectById(allowVO.getApplyId());
            QueryWrapper<SmsCarWarehousing> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda().and(wrapper -> {
                wrapper.eq(SmsCarWarehousing::getCarStatus, CAR_STATUS_OUT)
                        .or()
                        .eq(SmsCarWarehousing::getCarStatus,CAR_STATUS_OUT_TIME);
            })

                        .eq(SmsCarWarehousing::getId, smsCarUseApplication.getCarId());
            SmsCarWarehousing smsCarWarehousing = smsCarWarehousingMapper.selectOne(queryWrapper);
            smsCarWarehousing.setCarStatus(CAR_STATUS_IN);
            smsCarWarehousingMapper.updateById(smsCarWarehousing);

            QueryWrapper<SmsCarUseApplication> queryWrapper1 = new QueryWrapper<>();
            queryWrapper1.lambda().eq(SmsCarUseApplication::getCarId,smsCarUseApplication.getCarId())
                                  .eq(SmsCarUseApplication::getIsReturn,0)
                                  ;
            SmsCarUseApplication smsCarUseApplication1 = smsCarUseApplicationMapper.selectOne(queryWrapper1);
            smsCarUseApplication1.setIsReturn(1);
            smsCarUseApplication1.setIsUse(2);
            smsCarUseApplicationMapper.updateById(smsCarUseApplication1);
        }

        //节点驳回 重置其余节点状态
        if (allowVO.getDetailAllowStatus() == CAR_USE_STATUS_DENY) {
            SmsCarUseReturnApplicationDetail updateDenyDetail =
                    new SmsCarUseReturnApplicationDetail();
            updateDenyDetail.setDetailAllowStatus(CAR_USE_STATUS_DENY_FINISH);
            smsCarUseReturnApplicationDetailMapper.update(updateDenyDetail, new QueryWrapper<SmsCarUseReturnApplicationDetail>()
                    .lambda()
                    .eq(SmsCarUseReturnApplicationDetail::getApplicationId, allowVO.getApplyId())
                    .eq(SmsCarUseReturnApplicationDetail::getDetailAllowStatus, CAR_USE_STATUS_WAIT_ALLOW));
        }


        //消息通知
        if (is_done) {
            boolean result_status = false;
            if (allowVO.getDetailAllowStatus() == CAR_USE_STATUS_PASS) {
                result_status = true;
            }
            newTipsUtil.allowFinishTips(allowVO.getApplyId(), user_id, result_status);
        } else {
            SmsCarUseReturnApplicationDetail nextDetail =
                    smsCarUseReturnApplicationDetailMapper.selectOne(new QueryWrapper<SmsCarUseReturnApplicationDetail>()
                            .lambda()
                            .eq(SmsCarUseReturnApplicationDetail::getApplicationId, allowVO.getApplyId())
                            .eq(SmsCarUseReturnApplicationDetail::getDetailSort, applicationDetail.getDetailSort() + 1));
            RangeTypeEnum rangeTypeEnum;
            if (nextDetail.getProcessIsApplicationEdit().equals(1)) {
                rangeTypeEnum = RangeTypeEnum.RANGE_TYPE_ENUM_PERSON;
            } else {
                if (nextDetail.getProcessObjectType() == CAR_USE_OBJECT_TYPE_ROLE) {
                    rangeTypeEnum = RangeTypeEnum.RANGE_TYPE_ENUM_ROLE;
                } else {
                    rangeTypeEnum = RangeTypeEnum.RANGE_TYPE_ENUM_PERSON;
                }
            }

            List<String> rangeIDList = new ArrayList<>();
            rangeIDList.add(nextDetail.getProcessObjectId());
            newTipsUtil.allowContinueTips(allowVO.getApplyId(),
                    user_id,
                    rangeTypeEnum,
                    rangeIDList,
                    nextDetail.getId());
        }
        return CommonResult.success();
    }

    @Override
    public ResponseResult getCarUseReturnApplicationOriginSettingProcess() {
        List<SmsCarUseReturnApplicationOriginSettingProcessResp> respList =
                smsCarUseReturnApplicationProcessMapper.selectList(new QueryWrapper<SmsCarUseReturnApplicationProcess>()
                        .lambda()
                        .eq(SmsCarUseReturnApplicationProcess::getProcessIsApplicationEdit, true)
                        .eq(SmsCarUseReturnApplicationProcess::getProcessIsUse, true)
                        .orderByAsc(SmsCarUseReturnApplicationProcess::getProcessSort))
                        .stream()
                        .map(process -> {
                            SmsCarUseReturnApplicationOriginSettingProcessResp smsCarUseOriginSettingProcessResp =
                                    new SmsCarUseReturnApplicationOriginSettingProcessResp();
                            BeanUtils.copyProperties(process, smsCarUseOriginSettingProcessResp);
                            return smsCarUseOriginSettingProcessResp;
                        })
                        .collect(Collectors.toList());
        return CommonResult.success(respList);
    }

    @Override
    public ResponseResult selectAllCarUseReturnApply(String apply_unit, Integer pageSize, Integer pageNum) {
        QueryWrapper<SmsCarUseReturnApplication> queryWrapper = new QueryWrapper<>();
        if (!isNullOrEmpty(apply_unit)) {
            queryWrapper.lambda().like(SmsCarUseReturnApplication::getReturnApplyDepartment, apply_unit);
        }
        queryWrapper.orderByDesc("create_time");
        Page<SmsCarUseReturnApplication> page = new Page<>(pageNum, pageSize);
        List<SmsCarUseReturnApplicationResp> collect;

        Page<SmsCarUseReturnApplication> appApplicationPage = smsCarUseReturnApplicationMapper.selectPage(page, queryWrapper);
        List<SmsCarUseReturnApplication> records = appApplicationPage.getRecords();
        collect = records.stream().map(appApplication -> {
            SmsCarUseReturnApplicationResp appApplicationResp = new SmsCarUseReturnApplicationResp();
            BeanUtils.copyProperties(appApplication, appApplicationResp);
            appApplicationResp.setCarName(appApplication.getCarName());
            appApplicationResp.setCarPic(appApplication.getCarPic());
            appApplicationResp.setCarPosition(appApplication.getCarPosition());
            appApplicationResp.setCarNum(appApplication.getCarNum());
            appApplicationResp.setApplicationId(appApplication.getId());
            SmsUser smsUser = cacheUtil.getUserInfo(appApplicationResp.getReturnApplyUserId());
            if (smsUser != null) {
                SmsCarUseReturnApplicationUserResp user = new SmsCarUseReturnApplicationUserResp();
                BeanUtils.copyProperties(smsUser, user);
                appApplicationResp.setApplyUserInfo(user);
            }

            return appApplicationResp;
        }).collect(Collectors.toList());

        int total = (int) page.getTotal();
        return CommonResult.success(collect, total);
    }

    @Override
    public Future<ResponseResult> tableDownload(String apply_id, HttpServletResponse response) {
        return null;
    }

    @Override
    public Future<ResponseResult> exportCarUseReturnApplication(SmsCarUseReturnApplicationExportReq exportReq, HttpServletResponse response) {
        return null;
    }

    @Override
    public ResponseResult selectReturnCar(Integer pageSize, Integer pageNum, String userId) {
        List<SmsCarWarehousingResp> collect = new ArrayList<>();
        QueryWrapper<SmsCarUseApplication> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(SmsCarUseApplication::getApplyUserId, userId)
                             .eq(SmsCarUseApplication::getIsReturn,0);
        List<SmsCarUseApplication> list = smsCarUseApplicationMapper.selectList(queryWrapper);
        if(list.isEmpty()){
            return CommonResult.success(collect);
        }
        List<String> carIdList = list.stream().map(SmsCarUseApplication::getCarId).collect(Collectors.toList());
        Page<SmsCarWarehousing> page = new Page<>(pageNum, pageSize);
        LambdaQueryWrapper<SmsCarWarehousing> queryWrapper1 = new LambdaQueryWrapper<SmsCarWarehousing>();
            queryWrapper1.in(SmsCarWarehousing::getId, carIdList)
                    .and(wrapper -> {
                        wrapper.eq(SmsCarWarehousing::getCarStatus, CAR_STATUS_OUT)
                                .or()
                                .eq(SmsCarWarehousing::getCarStatus,CAR_STATUS_OUT_TIME);
                    } );

        Page<SmsCarWarehousing> smsCarWarehousingPage = smsCarWarehousingMapper.selectPage(page, queryWrapper1);
        collect = smsCarWarehousingPage.getRecords().stream().map(carOutInfo -> {
            SmsCarWarehousingResp smsCarWarehousingResp = new SmsCarWarehousingResp();
            BeanUtils.copyProperties(carOutInfo, smsCarWarehousingResp);
            return smsCarWarehousingResp;
        }).collect(Collectors.toList());

        int total = (int) page.getTotal();
        return CommonResult.success(collect, total);
    }
}
